home *** CD-ROM | disk | FTP | other *** search
/ Windows Game Programming for Dummies (2nd Edition) / WinGamProgFD.iso / pc / DirectX SDK / DXSDK / samples / Multimedia / DirectPlay / SimpleClientServer / SimpleServer / simpleserver.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2001-10-31  |  25.3 KB  |  694 lines

  1. //----------------------------------------------------------------------------
  2. // File: SimpleServer.cpp
  3. //
  4. // Desc: The SimpleClientServer sample is a simple client/server application. 
  5. //
  6. // Copyright (c) 1999-2001 Microsoft Corp. All rights reserved.
  7. //-----------------------------------------------------------------------------
  8. #define STRICT
  9. #include <windows.h>
  10. #include <basetsd.h>
  11. #include <dplay8.h>
  12. #include <dpaddr.h>
  13. #include <dxerr8.h>
  14. #include <tchar.h>
  15. #include "SimpleClientServer.h"
  16. #include "DXUtil.h"
  17. #include "resource.h"
  18.  
  19.  
  20.  
  21.  
  22. //-----------------------------------------------------------------------------
  23. // Player context locking defines
  24. //-----------------------------------------------------------------------------
  25. CRITICAL_SECTION g_csPlayerContext;
  26. #define PLAYER_LOCK()                   EnterCriticalSection( &g_csPlayerContext ); 
  27. #define PLAYER_ADDREF( pPlayerInfo )    if( pPlayerInfo ) pPlayerInfo->lRefCount++;
  28. #define PLAYER_RELEASE( pPlayerInfo )   if( pPlayerInfo ) { pPlayerInfo->lRefCount--; if( pPlayerInfo->lRefCount <= 0 ) SAFE_DELETE( pPlayerInfo ); } pPlayerInfo = NULL;
  29. #define PLAYER_UNLOCK()                 LeaveCriticalSection( &g_csPlayerContext );
  30.  
  31.  
  32. //-----------------------------------------------------------------------------
  33. // Defines, and constants
  34. //-----------------------------------------------------------------------------
  35. #define SIMPLESERVER_DEFAULT_PORT           0x6501 // arbitrary port number for this app
  36.  
  37. struct APP_PLAYER_INFO
  38. {
  39.     LONG  lRefCount;                        // Ref count so we can cleanup when all threads 
  40.                                             // are done w/ this object
  41.     DPNID dpnidPlayer;                      // DPNID of player
  42.     TCHAR strPlayerName[MAX_PLAYER_NAME];   // Player name
  43. };
  44.  
  45.  
  46.  
  47.  
  48. //-----------------------------------------------------------------------------
  49. // Global variables
  50. //-----------------------------------------------------------------------------
  51. IDirectPlay8Server* g_pDPServer                  = NULL;    // DirectPlay server object
  52. HINSTANCE          g_hInst                       = NULL;    // HINST of app
  53. HWND               g_hDlg                        = NULL;    // HWND of main dialog
  54. LONG               g_lNumberOfActivePlayers      = 0;       // Number of players currently in game
  55. TCHAR              g_strAppName[256]             = TEXT("SimpleServer");
  56. TCHAR              g_strSessionName[MAX_PATH];              // Session name
  57. DWORD              g_dwPort;                                // Port
  58. HRESULT            g_hrDialog;                              // Exit code for app 
  59. BOOL               g_bServerStarted              = FALSE;   // TRUE if the server has started
  60.  
  61.  
  62.  
  63.  
  64. //-----------------------------------------------------------------------------
  65. // Function-prototypes
  66. //-----------------------------------------------------------------------------
  67. HRESULT WINAPI   DirectPlayMessageHandler( PVOID pvUserContext, DWORD dwMessageId, PVOID pMsgBuffer );
  68. INT_PTR CALLBACK ServerDlgProc( HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam );
  69. HRESULT  StartServer( HWND hDlg );
  70. VOID     StopServer( HWND hDlg );
  71. VOID     DisplayPlayers( HWND hDlg );
  72. HRESULT  SendCreatePlayerMsg( APP_PLAYER_INFO* pPlayerInfo, DPNID dpnidTarget );
  73. HRESULT  SendWorldStateToNewPlayer( DPNID dpnidPlayer );
  74. HRESULT  SendDestroyPlayerMsgToAll( APP_PLAYER_INFO* pPlayerInfo );
  75. HRESULT  SendWaveMessageToAll( DPNID dpnidFrom );
  76.  
  77.  
  78.  
  79.  
  80.  
  81. //-----------------------------------------------------------------------------
  82. // Name: WinMain()
  83. // Desc: Entry point for the application.  Since we use a simple dialog for 
  84. //       user interaction we don't need to pump messages.
  85. //-----------------------------------------------------------------------------
  86. INT APIENTRY WinMain( HINSTANCE hInst, HINSTANCE hPrevInst, 
  87.                       LPSTR pCmdLine, INT nCmdShow )
  88. {
  89.     HKEY    hDPlaySampleRegKey;
  90.     BOOL    bConnectSuccess = FALSE;
  91.  
  92.     g_hInst = hInst; 
  93.     InitializeCriticalSection( &g_csPlayerContext );
  94.  
  95.     // Read persistent state information from registry
  96.     RegCreateKeyEx( HKEY_CURRENT_USER, DPLAY_SAMPLE_KEY, 0, NULL,
  97.                     REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, 
  98.                     &hDPlaySampleRegKey, NULL );
  99.     DXUtil_ReadStringRegKey( hDPlaySampleRegKey, TEXT("Session Name"), 
  100.                              g_strSessionName, MAX_PATH, TEXT("TestGame") );
  101.     DXUtil_ReadIntRegKey( hDPlaySampleRegKey, TEXT("SimpleServer Port"), 
  102.                           &g_dwPort, SIMPLESERVER_DEFAULT_PORT );
  103.  
  104.     // Init COM so we can use CoCreateInstance
  105.     CoInitializeEx( NULL, COINIT_MULTITHREADED );
  106.  
  107.     // For this sample, we just start a simple dialog box server
  108.     g_hrDialog = S_OK;
  109.     DialogBox( hInst, MAKEINTRESOURCE(IDD_MAIN), NULL, (DLGPROC) ServerDlgProc );
  110.  
  111.     if( FAILED( g_hrDialog ) )
  112.     {
  113.         if( g_hrDialog == DPNERR_CONNECTIONLOST )
  114.         {
  115.             MessageBox( NULL, TEXT("The DirectPlay session was lost. ")
  116.                         TEXT("The server will now quit."),
  117.                         g_strAppName, MB_OK | MB_ICONERROR );
  118.         }
  119.         else
  120.         {
  121.             DXTRACE_ERR( TEXT("DialogBox"), g_hrDialog );
  122.             MessageBox( NULL, TEXT("An error occured. ")
  123.                         TEXT("The server will now quit."),
  124.                         g_strAppName, MB_OK | MB_ICONERROR );
  125.         }
  126.     }
  127.  
  128.     DXUtil_WriteStringRegKey( hDPlaySampleRegKey, TEXT("Session Name"), g_strSessionName );
  129.     DXUtil_WriteIntRegKey( hDPlaySampleRegKey, TEXT("SimpleServer Port"), g_dwPort );
  130.  
  131.     StopServer( NULL );
  132.  
  133.     RegCloseKey( hDPlaySampleRegKey );
  134.     DeleteCriticalSection( &g_csPlayerContext );
  135.     CoUninitialize();
  136.  
  137.     return TRUE;
  138. }
  139.  
  140.  
  141.  
  142.  
  143. //-----------------------------------------------------------------------------
  144. // Name: ServerDlgProc()
  145. // Desc: Handles dialog messages
  146. //-----------------------------------------------------------------------------
  147. INT_PTR CALLBACK ServerDlgProc( HWND hDlg, UINT msg, 
  148.                                 WPARAM wParam, LPARAM lParam )
  149. {
  150.     switch( msg ) 
  151.     {
  152.         case WM_INITDIALOG:
  153.         {
  154.             g_hDlg = hDlg;
  155.  
  156.             // Load and set the icon
  157.             HICON hIcon = LoadIcon( g_hInst, MAKEINTRESOURCE( IDI_MAIN ) );
  158.             SendMessage( hDlg, WM_SETICON, ICON_BIG,   (LPARAM) hIcon );  // Set big icon
  159.             SendMessage( hDlg, WM_SETICON, ICON_SMALL, (LPARAM) hIcon );  // Set small icon
  160.  
  161.             SetWindowText( hDlg, TEXT("SimpleServer") );
  162.             SetDlgItemText( hDlg, IDC_SESSION_NAME, g_strSessionName );
  163.  
  164.             // Set the port to either a number or blank
  165.             if( g_dwPort != 0 )
  166.                 SetDlgItemInt( hDlg, IDC_PORT, g_dwPort, FALSE );
  167.             else
  168.                 SetDlgItemText( hDlg, IDC_PORT, TEXT("") );
  169.  
  170.             SetDlgItemText( hDlg, IDC_STATUS, TEXT("Server stoped.") );
  171.  
  172.             PostMessage( hDlg, WM_APP_UPDATE_STATS, 0, 0 );
  173.             break;
  174.         }
  175.  
  176.         case WM_APP_UPDATE_STATS:
  177.         {
  178.             // Update the number of players in the game
  179.             TCHAR strNumberPlayers[32];
  180.  
  181.             wsprintf( strNumberPlayers, TEXT("%d"), g_lNumberOfActivePlayers );
  182.             SetDlgItemText( hDlg, IDC_NUM_PLAYERS, strNumberPlayers );
  183.             DisplayPlayers( hDlg );
  184.             break;
  185.         }
  186.  
  187.         case WM_COMMAND:
  188.         {
  189.             switch( LOWORD(wParam) )
  190.             {
  191.                 case IDC_START:
  192.                     if( !g_bServerStarted )
  193.                     {
  194.                         if( FAILED( g_hrDialog = StartServer( hDlg ) ) )
  195.                         {
  196.                             DXTRACE_ERR( TEXT("StartServer"), g_hrDialog );
  197.                             EndDialog( hDlg, 0 );
  198.                         }
  199.                     }
  200.                     else
  201.                     {
  202.                         StopServer( hDlg );
  203.                     }
  204.  
  205.                     if( g_bServerStarted )
  206.                     {
  207.                         SetDlgItemText( hDlg, IDC_START, TEXT("Stop Server") );
  208.                         EnableWindow( GetDlgItem( hDlg, IDC_SESSION_NAME ), FALSE );
  209.                         EnableWindow( GetDlgItem( hDlg, IDC_PORT ), FALSE );
  210.                     }
  211.                     else
  212.                     {
  213.                         SetDlgItemText( hDlg, IDC_START, TEXT("Start Server") );
  214.                         EnableWindow( GetDlgItem( hDlg, IDC_SESSION_NAME ), TRUE );
  215.                         EnableWindow( GetDlgItem( hDlg, IDC_PORT ), TRUE );
  216.                     }
  217.  
  218.                     break;
  219.  
  220.                 case IDCANCEL:
  221.                     StopServer( hDlg );
  222.                     EndDialog( hDlg, 0 );
  223.                     return TRUE;
  224.             }
  225.             break;
  226.         }
  227.     }
  228.  
  229.     return FALSE; // Didn't handle message
  230. }
  231.  
  232.  
  233.  
  234.  
  235. //-----------------------------------------------------------------------------
  236. // Name: DirectPlayMessageHandler
  237. // Desc: Handler for DirectPlay messages.  This function is called by
  238. //       the DirectPlay message handler pool of threads, so be careful of thread
  239. //       synchronization problems with shared memory
  240. //-----------------------------------------------------------------------------
  241. HRESULT WINAPI DirectPlayMessageHandler( PVOID pvUserContext, 
  242.                                          DWORD dwMessageId, 
  243.                                          PVOID pMsgBuffer )
  244. {
  245.     // Try not to stay in this message handler for too long, otherwise
  246.     // there will be a backlog of data.  The best solution is to 
  247.     // queue data as it comes in, and then handle it on other threads.
  248.     
  249.     // This function is called by the DirectPlay message handler pool of 
  250.     // threads, so be careful of thread synchronization problems with shared memory
  251.  
  252.     switch( dwMessageId )
  253.     {
  254.         case DPN_MSGID_CREATE_PLAYER:
  255.         {
  256.             HRESULT hr;
  257.             PDPNMSG_CREATE_PLAYER pCreatePlayerMsg;
  258.             pCreatePlayerMsg = (PDPNMSG_CREATE_PLAYER)pMsgBuffer;
  259.  
  260.             // Get the peer info and extract its name
  261.             DWORD dwSize = 0;
  262.             DPN_PLAYER_INFO* pdpPlayerInfo = NULL;
  263.             hr = g_pDPServer->GetClientInfo( pCreatePlayerMsg->dpnidPlayer, 
  264.                                              pdpPlayerInfo, &dwSize, 0 );
  265.             if( FAILED(hr) && hr != DPNERR_BUFFERTOOSMALL )
  266.             {
  267.                 if( hr == DPNERR_INVALIDPLAYER )
  268.                 {
  269.                     // Ignore this message if this is for the host
  270.                     break;
  271.                 }
  272.  
  273.                 return DXTRACE_ERR( TEXT("GetClientInfo"), hr );
  274.             }
  275.             pdpPlayerInfo = (DPN_PLAYER_INFO*) new BYTE[ dwSize ];
  276.             ZeroMemory( pdpPlayerInfo, dwSize );
  277.             pdpPlayerInfo->dwSize = sizeof(DPN_PLAYER_INFO);
  278.             hr = g_pDPServer->GetClientInfo( pCreatePlayerMsg->dpnidPlayer, 
  279.                                        pdpPlayerInfo, &dwSize, 0 );
  280.             if( FAILED(hr) )
  281.                 return DXTRACE_ERR( TEXT("GetClientInfo"), hr );
  282.  
  283.             // Create a new and fill in a APP_PLAYER_INFO
  284.             APP_PLAYER_INFO* pPlayerInfo = new APP_PLAYER_INFO;
  285.             ZeroMemory( pPlayerInfo, sizeof(APP_PLAYER_INFO) );
  286.             pPlayerInfo->lRefCount   = 1;
  287.             pPlayerInfo->dpnidPlayer = pCreatePlayerMsg->dpnidPlayer;
  288.  
  289.             // This stores a extra TCHAR copy of the player name for 
  290.             // easier access.  This will be redundent copy since DPlay 
  291.             // also keeps a copy of the player name in GetClientInfo()
  292.             DXUtil_ConvertWideStringToGeneric( pPlayerInfo->strPlayerName, 
  293.                                                pdpPlayerInfo->pwszName, MAX_PLAYER_NAME );
  294.  
  295.             SAFE_DELETE_ARRAY( pdpPlayerInfo );
  296.  
  297.             // Tell DirectPlay to store this pPlayerInfo 
  298.             // pointer in the pvPlayerContext.
  299.             pCreatePlayerMsg->pvPlayerContext = pPlayerInfo;
  300.  
  301.             // Send all connected players a message telling about this new player
  302.             SendCreatePlayerMsg( pPlayerInfo, DPNID_ALL_PLAYERS_GROUP );
  303.  
  304.             // Tell this new player about the world state
  305.             SendWorldStateToNewPlayer( pCreatePlayerMsg->dpnidPlayer );
  306.  
  307.             // Update the number of active players, and 
  308.             // post a message to the dialog thread to update the 
  309.             // UI.  This keeps the DirectPlay message handler 
  310.             // from blocking
  311.             InterlockedIncrement( &g_lNumberOfActivePlayers );
  312.             if( g_hDlg != NULL )
  313.                 PostMessage( g_hDlg, WM_APP_UPDATE_STATS, 0, 0 );
  314.  
  315.             break;
  316.         }
  317.  
  318.         case DPN_MSGID_DESTROY_PLAYER:
  319.         {
  320.             PDPNMSG_DESTROY_PLAYER pDestroyPlayerMsg;
  321.             pDestroyPlayerMsg = (PDPNMSG_DESTROY_PLAYER)pMsgBuffer;
  322.             APP_PLAYER_INFO* pPlayerInfo = (APP_PLAYER_INFO*) pDestroyPlayerMsg->pvPlayerContext;
  323.  
  324.             // Ignore this message if this is the host player
  325.             if( pPlayerInfo == NULL )
  326.                 break; 
  327.  
  328.             // Send all connected players a message telling about this destroyed player
  329.             SendDestroyPlayerMsgToAll( pPlayerInfo );
  330.  
  331.             PLAYER_LOCK();                  // enter player context CS
  332.             PLAYER_RELEASE( pPlayerInfo );  // Release player and cleanup if needed
  333.             PLAYER_UNLOCK();                // leave player context CS
  334.  
  335.             // Update the number of active players, and 
  336.             // post a message to the dialog thread to update the 
  337.             // UI.  This keeps the DirectPlay message handler 
  338.             // from blocking
  339.             InterlockedDecrement( &g_lNumberOfActivePlayers );
  340.             if( g_hDlg != NULL )
  341.                 PostMessage( g_hDlg, WM_APP_UPDATE_STATS, 0, 0 );
  342.  
  343.             break;
  344.         }
  345.  
  346.         case DPN_MSGID_TERMINATE_SESSION:
  347.         {
  348.             PDPNMSG_TERMINATE_SESSION pTerminateSessionMsg;
  349.             pTerminateSessionMsg = (PDPNMSG_TERMINATE_SESSION)pMsgBuffer;
  350.  
  351.             g_hrDialog = DPNERR_CONNECTIONLOST;
  352.             EndDialog( g_hDlg, 0 );
  353.             break;
  354.         }
  355.  
  356.         case DPN_MSGID_RECEIVE:
  357.         {
  358.             PDPNMSG_RECEIVE pReceiveMsg;
  359.             pReceiveMsg = (PDPNMSG_RECEIVE)pMsgBuffer;
  360.             APP_PLAYER_INFO* pPlayerInfo = (APP_PLAYER_INFO*) pReceiveMsg->pvPlayerContext;
  361.  
  362.             GAMEMSG_GENERIC* pMsg = (GAMEMSG_GENERIC*) pReceiveMsg->pReceiveData;
  363.             if( pMsg->dwType == GAME_MSGID_WAVE )
  364.                 SendWaveMessageToAll( pPlayerInfo->dpnidPlayer );
  365.             break;
  366.         }
  367.     }
  368.  
  369.     return S_OK;
  370. }
  371.  
  372.  
  373.  
  374.  
  375. //-----------------------------------------------------------------------------
  376. // Name: StartServer
  377. // Desc: 
  378. //-----------------------------------------------------------------------------
  379. HRESULT StartServer( HWND hDlg )
  380. {
  381.     HRESULT hr;
  382.     PDIRECTPLAY8ADDRESS pDP8AddrLocal = NULL;
  383.  
  384.     SetDlgItemText( hDlg, IDC_STATUS, TEXT("Starting server...") );
  385.     SetCursor( LoadCursor(NULL, IDC_WAIT) );
  386.  
  387.     WCHAR wstrSessionName[MAX_PATH];
  388.     GetDlgItemText( hDlg, IDC_SESSION_NAME, g_strSessionName, MAX_PATH );
  389.     DXUtil_ConvertGenericStringToWide( wstrSessionName, g_strSessionName );
  390.  
  391.     BOOL bPortTranslated;
  392.     g_dwPort = GetDlgItemInt( hDlg, IDC_PORT, &bPortTranslated, FALSE );
  393.     if( !bPortTranslated )
  394.         g_dwPort = 0;
  395.  
  396.     // Create IDirectPlay8Server
  397.     if( FAILED( hr = CoCreateInstance( CLSID_DirectPlay8Server, NULL, 
  398.                                        CLSCTX_INPROC_SERVER,
  399.                                        IID_IDirectPlay8Server, 
  400.                                        (LPVOID*) &g_pDPServer ) ) )
  401.         return DXTRACE_ERR( TEXT("CoCreateInstance"), hr );
  402.  
  403.     // Init IDirectPlay8Server
  404.     if( FAILED( hr = g_pDPServer->Initialize( NULL, DirectPlayMessageHandler, 0 ) ) )
  405.         return DXTRACE_ERR( TEXT("Initialize"), hr );
  406.  
  407.     hr = CoCreateInstance( CLSID_DirectPlay8Address, NULL, 
  408.                            CLSCTX_ALL, IID_IDirectPlay8Address, 
  409.                            (LPVOID*) &pDP8AddrLocal );
  410.     if( FAILED(hr) )
  411.     {
  412.         DXTRACE_ERR( TEXT("CoCreateInstance"), hr );
  413.         goto LCleanup;
  414.     }
  415.  
  416.     hr = pDP8AddrLocal->SetSP( &CLSID_DP8SP_TCPIP );
  417.     if( FAILED(hr) )
  418.     {
  419.         DXTRACE_ERR( TEXT("SetSP"), hr );
  420.         goto LCleanup;
  421.     }
  422.  
  423.     // Add the port to pDP8AddrLocal, if the port is non-zero.
  424.     // If the port is 0, then DirectPlay will pick a port, 
  425.     // Games will typically hard code the port so the 
  426.     // user need not know it
  427.     if( g_dwPort != 0 )
  428.     {
  429.         if( FAILED( hr = pDP8AddrLocal->AddComponent( DPNA_KEY_PORT, 
  430.                                                       &g_dwPort, sizeof(g_dwPort),
  431.                                                       DPNA_DATATYPE_DWORD ) ) )
  432.             return DXTRACE_ERR( TEXT("AddComponent"), hr );
  433.     }
  434.  
  435.     DPN_APPLICATION_DESC dpnAppDesc;
  436.     ZeroMemory( &dpnAppDesc, sizeof(DPN_APPLICATION_DESC) );
  437.     dpnAppDesc.dwSize           = sizeof( DPN_APPLICATION_DESC );
  438.     dpnAppDesc.dwFlags          = DPNSESSION_CLIENT_SERVER;
  439.     dpnAppDesc.guidApplication  = g_guidApp;
  440.     dpnAppDesc.pwszSessionName  = wstrSessionName;
  441.  
  442.     hr = g_pDPServer->Host( &dpnAppDesc, &pDP8AddrLocal, 1, NULL, NULL, NULL, 0  );
  443.     if( FAILED(hr) )
  444.     {
  445.         DXTRACE_ERR( TEXT("Host"), hr );
  446.         goto LCleanup;
  447.     }
  448.  
  449.     SetCursor( LoadCursor(NULL, IDC_ARROW) );
  450.     g_bServerStarted = TRUE;
  451.     SetDlgItemText( hDlg, IDC_STATUS, TEXT("Server started.") );
  452.  
  453. LCleanup:
  454.     SAFE_RELEASE( pDP8AddrLocal );
  455.  
  456.     return hr;
  457. }
  458.  
  459.  
  460.  
  461.  
  462. //-----------------------------------------------------------------------------
  463. // Name: StopServer
  464. // Desc: 
  465. //-----------------------------------------------------------------------------
  466. VOID StopServer( HWND hDlg )
  467. {
  468.     if( hDlg )
  469.         SetDlgItemText( hDlg, IDC_STATUS, TEXT("Stopping server...") );
  470.     SetCursor( LoadCursor(NULL, IDC_WAIT) );
  471.  
  472.     if( g_pDPServer )
  473.     {
  474.         g_pDPServer->Close(0);
  475.         SAFE_RELEASE( g_pDPServer );
  476.     }
  477.     g_bServerStarted = FALSE;
  478.  
  479.     SetCursor( LoadCursor(NULL, IDC_ARROW) );
  480.     if( hDlg )
  481.         SetDlgItemText( hDlg, IDC_STATUS, TEXT("Server stoped.") );
  482. }
  483.  
  484.  
  485.  
  486.     
  487. //-----------------------------------------------------------------------------
  488. // Name: DisplayPlayers
  489. // Desc: 
  490. //-----------------------------------------------------------------------------
  491. VOID DisplayPlayers( HWND hDlg )
  492. {
  493.     HRESULT hr;
  494.     DWORD dwNumPlayers = 0;
  495.     DPNID* aPlayers = NULL;
  496.  
  497.     SendMessage( GetDlgItem(hDlg, IDC_PLAYER_LIST), LB_RESETCONTENT, 0, 0 );
  498.  
  499.     if( NULL == g_pDPServer )
  500.         return;
  501.  
  502.     // Enumerate all the connected players
  503.     while( TRUE )
  504.     {
  505.         hr = g_pDPServer->EnumPlayersAndGroups( aPlayers, &dwNumPlayers, DPNENUM_PLAYERS );
  506.         if( SUCCEEDED(hr) )
  507.             break;
  508.  
  509.         if( FAILED(hr) && hr != DPNERR_BUFFERTOOSMALL )
  510.             return;
  511.  
  512.         SAFE_DELETE_ARRAY( aPlayers );
  513.         aPlayers = new DPNID[ dwNumPlayers ];
  514.     }
  515.  
  516.     // For each player, send a "create player" message to the new player
  517.     for( DWORD i = 0; i<dwNumPlayers; i++ )
  518.     {
  519.         APP_PLAYER_INFO* pPlayerInfo = NULL;
  520.  
  521.         do
  522.         {
  523.             // Get the player context accosicated with this DPNID
  524.             // Call GetPlayerContext() until it returns something other than DPNERR_NOTREADY
  525.             // DPNERR_NOTREADY will be returned if the callback thread has not 
  526.             // yet returned from DPN_MSGID_CREATE_PLAYER, which sets the player's context
  527.             hr = g_pDPServer->GetPlayerContext( aPlayers[i], (LPVOID*) &pPlayerInfo, 0 );
  528.         } 
  529.         while( hr == DPNERR_NOTREADY ); 
  530.                 
  531.         // Ignore this player if we can't get the context
  532.         if( pPlayerInfo == NULL || FAILED(hr) )
  533.             continue; 
  534.         
  535.         TCHAR strTemp[MAX_PATH];
  536.         wsprintf( strTemp, TEXT("DPNID: 0x%0.8x (%s)"), pPlayerInfo->dpnidPlayer, pPlayerInfo->strPlayerName );
  537.         int nIndex = (int)SendMessage( GetDlgItem(hDlg, IDC_PLAYER_LIST), LB_ADDSTRING, 
  538.                                        0, (LPARAM)strTemp );
  539.     }
  540.  
  541.     SAFE_DELETE_ARRAY( aPlayers );
  542. }
  543.  
  544.  
  545.  
  546.     
  547. //-----------------------------------------------------------------------------
  548. // Name: SendCreatePlayerMsg
  549. // Desc: Send the target player a creation message about the player identified
  550. //       in the APP_PLAYER_INFO struct.
  551. //-----------------------------------------------------------------------------
  552. HRESULT SendCreatePlayerMsg( APP_PLAYER_INFO* pPlayerAbout, DPNID dpnidTarget )
  553. {
  554.     GAMEMSG_CREATE_PLAYER msgCreatePlayer;
  555.     msgCreatePlayer.dwType = GAME_MSGID_CREATE_PLAYER;
  556.     msgCreatePlayer.dpnidPlayer = pPlayerAbout->dpnidPlayer;
  557.     _tcscpy( msgCreatePlayer.strPlayerName, pPlayerAbout->strPlayerName );
  558.  
  559.     DPN_BUFFER_DESC bufferDesc;
  560.     bufferDesc.dwBufferSize = sizeof(GAMEMSG_CREATE_PLAYER);
  561.     bufferDesc.pBufferData  = (BYTE*) &msgCreatePlayer;
  562.  
  563.     // DirectPlay will tell via the message handler 
  564.     // if there are any severe errors, so ignore any errors 
  565.     DPNHANDLE hAsync;
  566.     g_pDPServer->SendTo( dpnidTarget, &bufferDesc, 1,
  567.                          0, NULL, &hAsync, DPNSEND_NOLOOPBACK | DPNSEND_GUARANTEED );
  568.  
  569.     return S_OK;
  570. }
  571.  
  572.  
  573.  
  574.     
  575. //-----------------------------------------------------------------------------
  576. // Name: SendWorldStateToNewPlayer
  577. // Desc: Send the world state to the new player.  For this sample, it is just
  578. //       "create player" message for every connected player
  579. //-----------------------------------------------------------------------------
  580. HRESULT SendWorldStateToNewPlayer( DPNID dpnidNewPlayer )
  581. {
  582.     HRESULT hr;
  583.     DWORD dwNumPlayers = 0;
  584.     DPNID* aPlayers = NULL;
  585.  
  586.     // Tell this player the dpnid of itself
  587.     GAMEMSG_SET_ID msgSetID;
  588.     msgSetID.dwType      = GAME_MSGID_SET_ID;
  589.     msgSetID.dpnidPlayer = dpnidNewPlayer;
  590.  
  591.     DPN_BUFFER_DESC bufferDesc;
  592.     bufferDesc.dwBufferSize = sizeof(GAMEMSG_SET_ID);
  593.     bufferDesc.pBufferData  = (BYTE*) &msgSetID;
  594.  
  595.     // DirectPlay will tell via the message handler 
  596.     // if there are any severe errors, so ignore any errors 
  597.     DPNHANDLE hAsync;
  598.     g_pDPServer->SendTo( dpnidNewPlayer, &bufferDesc, 1,
  599.                          0, NULL, &hAsync, DPNSEND_NOLOOPBACK | DPNSEND_GUARANTEED );
  600.  
  601.     // Enumerate all the connected players
  602.     while( TRUE )
  603.     {
  604.         hr = g_pDPServer->EnumPlayersAndGroups( aPlayers, &dwNumPlayers, DPNENUM_PLAYERS );
  605.         if( SUCCEEDED(hr) )
  606.             break;
  607.  
  608.         if( FAILED(hr) && hr != DPNERR_BUFFERTOOSMALL )
  609.             return DXTRACE_ERR( TEXT("EnumPlayersAndGroups"), hr );
  610.  
  611.         SAFE_DELETE_ARRAY( aPlayers );
  612.         aPlayers = new DPNID[ dwNumPlayers ];
  613.     }
  614.  
  615.     // For each player, send a "create player" message to the new player
  616.     for( DWORD i = 0; i<dwNumPlayers; i++ )
  617.     {
  618.         APP_PLAYER_INFO* pPlayerInfo = NULL;
  619.  
  620.         // Don't send a create msg to the new player about itself.  This will 
  621.         // be already done when we sent one to DPNID_ALL_PLAYERS_GROUP
  622.         if( aPlayers[i] == dpnidNewPlayer )
  623.             continue;  
  624.  
  625.         // Get the player context accosicated with this DPNID
  626.         hr = g_pDPServer->GetPlayerContext( aPlayers[i], (LPVOID*) &pPlayerInfo, 0 );
  627.  
  628.         // Ignore this player if we can't get the context
  629.         if( pPlayerInfo == NULL || FAILED(hr) )
  630.             continue; 
  631.  
  632.         SendCreatePlayerMsg( pPlayerInfo, dpnidNewPlayer );
  633.     }
  634.  
  635.     SAFE_DELETE_ARRAY( aPlayers );
  636.  
  637.     return S_OK;
  638. }
  639.  
  640.  
  641.  
  642.  
  643. //-----------------------------------------------------------------------------
  644. // Name: SendDestroyPlayerMsgToAll
  645. // Desc: 
  646. //-----------------------------------------------------------------------------
  647. HRESULT SendDestroyPlayerMsgToAll( APP_PLAYER_INFO* pPlayerInfo )
  648. {
  649.     GAMEMSG_DESTROY_PLAYER msgDestroyPlayer;
  650.     msgDestroyPlayer.dwType = GAME_MSGID_DESTROY_PLAYER;
  651.     msgDestroyPlayer.dpnidPlayer = pPlayerInfo->dpnidPlayer;
  652.  
  653.     DPN_BUFFER_DESC bufferDesc;
  654.     bufferDesc.dwBufferSize = sizeof(GAMEMSG_CREATE_PLAYER);
  655.     bufferDesc.pBufferData  = (BYTE*) &msgDestroyPlayer;
  656.  
  657.     // DirectPlay will tell via the message handler 
  658.     // if there are any severe errors, so ignore any errors 
  659.     DPNHANDLE hAsync;
  660.     g_pDPServer->SendTo( DPNID_ALL_PLAYERS_GROUP, &bufferDesc, 1,
  661.                          0, NULL, &hAsync, DPNSEND_NOLOOPBACK | DPNSEND_GUARANTEED );
  662.  
  663.     return S_OK;
  664. }
  665.  
  666.  
  667.  
  668.  
  669. //-----------------------------------------------------------------------------
  670. // Name: SendWaveMessageToAll
  671. // Desc: 
  672. //-----------------------------------------------------------------------------
  673. HRESULT SendWaveMessageToAll( DPNID dpnidFrom )
  674. {
  675.     GAMEMSG_WAVE msgWave;
  676.     msgWave.dwType = GAME_MSGID_WAVE;
  677.     msgWave.dpnidPlayer = dpnidFrom;
  678.  
  679.     DPN_BUFFER_DESC bufferDesc;
  680.     bufferDesc.dwBufferSize = sizeof(GAMEMSG_WAVE);
  681.     bufferDesc.pBufferData  = (BYTE*) &msgWave;
  682.  
  683.     // DirectPlay will tell via the message handler 
  684.     // if there are any severe errors, so ignore any errors 
  685.     DPNHANDLE hAsync;
  686.     g_pDPServer->SendTo( DPNID_ALL_PLAYERS_GROUP, &bufferDesc, 1,
  687.                          0, NULL, &hAsync, DPNSEND_NOLOOPBACK | DPNSEND_GUARANTEED );
  688.  
  689.     return S_OK;
  690. }
  691.  
  692.  
  693.  
  694.